#include "NRJB/NRJBConnection.h"
#include "PacketConstructer.h"
#include "NRJB/NRJB103Constructer.h"
#include <QtNetwork/QNetworkInterface>
NRJBConnection::NRJBConnection()
{
    m_tcpClientSocket = new QTcpSocket;
    QObject::connect(m_tcpClientSocket, &QTcpSocket::readyRead, this, &NRJBConnection::onRecvTcpMsg);
    QObject::connect(m_tcpClientSocket, &QTcpSocket::disconnected, this, &NRJBConnection::onSocketDisconnected);
    QObject::connect(m_tcpClientSocket, &QTcpSocket::connected, this, &NRJBConnection::slot_connectSuccess);
    QObject::connect(&m_heartTimer, &QTimer::timeout, this, &NRJBConnection::slot_sendeartBeatMsg);
    m_dataNo = 0;

    m_timerConnct.setInterval(500);
    m_connectTimeLimit = 10;
    connect(&m_timerConnct, &QTimer::timeout, this, &NRJBConnection::slot_connectDevice);

    //connect(&m_timerSendCmdList, &QTimer::timeout, this, &NRJBConnection::slot_sendTcpMsgList);

    // 使用收到回答后间隔10ms再发送下一条命令的方式, 30次反复测试保护都正常回答了所有数据请求
   connect(m_tcpClientSocket, &QTcpSocket::readyRead, this, &NRJBConnection::slot_sendTcpMsgListNextOne);
}

NRJBConnection::~NRJBConnection()
{
    delete m_tcpClientSocket;
   // delete m_server;
}

void NRJBConnection::setIPPortAndConnect(const QString &destDevIp, const QString &localIp, const QString &port)
{
    m_destDevAddr = destDevIp;
    m_port = port;
    m_localAddr = localIp;
    // 103报文中的 asdu 的cpu服务地址 apci 中占两个字节 0xdc00 ,asdu占一个字节0xdc

    m_destDevAddrLastPart =  Utils::uintStrToHexStr(destDevIp.split('.')[3], 4);    // 4个字符的地址表示形式
    qDebug() << "cpu服务地址也就是目标设备的ip地址的最后一格字段的16进制数 m_destDevAddrLastPart = "<< m_destDevAddrLastPart;
    m_cpuAddr = Utils::uintStrToHexStr(destDevIp.split('.')[3], 2);
    qDebug() << "目标设备地址的最后一格字段 m_cpuAddr = "<< m_cpuAddr;

    m_localAddrLastPart = Utils::uintStrToHexStr(localIp.split('.')[3], 4);
    qDebug() << "源设备地址的最后一格字段4位 m_srcDevAddr = "<< m_localAddrLastPart;

    //连接设备
    if (m_timerConnct.isActive() == false )
    {
        m_connectTimeLimit = 10;        // 重新给十次机会
        m_timerConnct.start(200);
    }
}

void NRJBConnection::sendTcpMsg(QString &msg)
{
    // 每次调用 发送都将 apci 的消息编号加17,18
    if(m_dataNo == 65535)
    {
        m_dataNo = 0;
    }

    m_dataNo++;
    // 将 数据编号转换成 16进制数字
    QString dataNoStr = Utils::intToHexStr(m_dataNo, 4);
    // 修改 msg 的 数据编号， 在报文的下标为 33,34,35,36
    QByteArray msgByte = QByteArray::fromHex( msg.replace(32,4,dataNoStr.toLatin1()).toLatin1());
    qDebug() << "tcp socket 发送 " << msgByte;

    m_tcpClientSocket->write(msgByte, msgByte.length());

    emit sig_sendMsg("[发送消息]: " + msgByte.toHex());
}

void NRJBConnection::sendTcpMsg(QByteArray &msg)
{
    // 每次调用 发送都将 apci 的消息编号加17,18
    m_dataNo++;
    qDebug() << "发送数据编号 = " << m_dataNo;
    // 将 数据编号转换成 16进制数字
    QString dataNoStr = Utils::intToHexStr(m_dataNo, 4);

    // 修改 msg 的 数据编号， 在报文的下标为 33,34,35,36
    msg[33] = dataNoStr.toLatin1()[0];
    msg[34] = dataNoStr.toLatin1()[1];
    msg[35] = dataNoStr.toLatin1()[2];
    msg[36] = dataNoStr.toLatin1()[3];

    int ret = m_tcpClientSocket->write(QByteArray::fromHex(msg), msg.length());   // 加入写入成功反馈

    // 发送失败的时候需要尝试重新发送
    qDebug() << "tcp 发送 ： "  << msg;
    if (ret == -1) {
        emit sig_sendMsg("[发送消息]: "+m_tcpClientSocket->errorString());
    }
    else {
        emit sig_sendMsg("[发送消息]: "+msg);
    }
}

void NRJBConnection::connectToDevice()
{
    quint16 peerPort(m_port.toUInt());

    // 设置超时响应
    int count = 5;
    while (count>0)
    {
        m_tcpClientSocket->connectToHost(m_destDevAddr, peerPort, QIODevice::ReadWrite);
        QThread::msleep(100);

        if (m_tcpClientSocket->state() == QAbstractSocket::ConnectedState)
        {
            // 发出来连接成功信号，client界面收到此信号刷新界面控件可否状态
            return;
        }

        count--;
    }

    return;
}

QByteArray NRJBConnection::getRecvTcpMsg()
{
    return m_recvBuffer;
}

void NRJBConnection::disconnectFromDevice()
{
    m_tcpClientSocket->disconnectFromHost();
    //m_clientState = 0;
    m_heartTimer.stop();
}

void NRJBConnection::startHeartTimer()
{
    m_heartTimer.start(1000);
}

void NRJBConnection::stopHeartTimer()
{
    m_heartTimer.stop();
}

void NRJBConnection::onSocketDisconnected()
{
    m_tcpClientSocket->disconnectFromHost();
    emit sig_disconnect();
    m_heartTimer.stop();

    m_tcpClientConnectedState = false;
}

void NRJBConnection::onRecvTcpMsg()
{
    m_recvBuffer = m_tcpClientSocket->readAll();
    emit sig_readyRead();
}


void NRJBConnection::slot_connectSuccess()
{
    //m_clientState =1;
    m_tcpClientSocket->open(QIODevice::ReadWrite);
    emit sig_connected();
    m_tcpClientConnectedState = true;
}

void NRJBConnection::slot_sendeartBeatMsg()
{
    // 目标设备地址
    ushort srcAddr = m_localAddrLastPart.toUInt(nullptr,16);
    ushort destAddr = m_destDevAddrLastPart.toUInt(nullptr,16);
    //m_tcpClientSocket->write(QByteArray::fromHex();  //本机地址最后字段 108

    QByteArray m_hearBeatMsg =  m_packetConstructer->constructHeartPacket(srcAddr, destAddr);
    sendTcpMsg(m_hearBeatMsg);
    //    qDebug() << "心跳报文: " << m_packetConstructer->constructHeartPacket(srcAddr, destAddr);
}

void NRJBConnection::slot_connectDevice()
{
    quint16 peerPort(m_port.toUInt());
    qDebug() << "现在准备连接到设备: " << m_destDevAddr << " port : " << peerPort;
    m_tcpClientSocket->connectToHost(m_destDevAddr, peerPort, QIODevice::ReadWrite);
    m_connectTimeLimit--;

    if (m_connectTimeLimit == 0)
    {
        emit sig_sendMsg("连接超时！");
        emit sig_connectTimeOut();
        qDebug() << "南瑞继保连接保护超时！";
        m_timerConnct.stop();
        m_connectTimeLimit = 10;
        return;
    }

    if (m_tcpClientSocket->state() == QAbstractSocket::ConnectedState)
    {
        // 发出来连接成功信号，client界面收到此信号刷新界面控件可否状态
        emit sig_sendMsg("连接成功。");
        qDebug() << "南瑞继保连接保护successed。";
        m_timerConnct.stop();
        m_connectTimeLimit = 10;
        return;
    }
}

void NRJBConnection::displayError(QAbstractSocket::SocketError socketError)
{
    switch (socketError) {
    case QAbstractSocket::RemoteHostClosedError:
        emit sig_sendMsg( "[错误] : the remote host closed error!");
        break;
    case QAbstractSocket::HostNotFoundError:
        emit sig_sendMsg( "[错误] : The host was not found. Please check the host name and port settings.");
        break;
    case QAbstractSocket::ConnectionRefusedError:
        emit sig_sendMsg( "[错误] : The connection was refused by the peer. "
                     "Make sure the fortune server is running, "
                     "and check that the host name and port "
                     "settings are correct.");
        break;
    default:
        emit sig_sendMsg( "[错误] :" + m_tcpClientSocket->errorString());
    }
}

QStringList NRJBConnection::getLocalHostIPList()
{
    QStringList strIpAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    int nListSize = ipAddressesList.size();
    for (int i = 0; i < nListSize; ++i)
    {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
                ipAddressesList.at(i).toIPv4Address()) {
            strIpAddress.append(ipAddressesList.at(i).toString());
        }
    }

    if (strIpAddress.isEmpty())
    {
        strIpAddress.append(QHostAddress(QHostAddress::LocalHost).toString());
    }

    return strIpAddress;
}

void NRJBConnection::sendTcpMsg(const QByteArrayList &msgList)
{
    m_cmdListReadBill = msgList;
    m_timerSendCmdList.start(SEND_INTERVEAL);
}

void NRJBConnection::slot_sendTcpMsgList()
{
    if ( m_indexSendCmdList == m_cmdListReadBill.count())
    {
        m_timerSendCmdList.stop();
        m_indexSendCmdList = 0;
        return;
    }
    QByteArray msg = m_cmdListReadBill.at(m_indexSendCmdList);
    sendTcpMsg(msg);
    m_indexSendCmdList++;
}

void NRJBConnection::slot_sendTcpMsgListNextOne()
{
    // 确认是否是发送 CMDList 的任务
    if (!m_timerSendCmdList.isActive()) {
        return;
    }

    // 发送完毕否检查
    if ( m_indexSendCmdList == m_cmdListReadBill.count())
    {
        m_timerSendCmdList.stop();
        m_indexSendCmdList = 0;
        return;
    }

    // 逐个发送报文命令
    QByteArray msg = m_cmdListReadBill.at(m_indexSendCmdList);
//    QThread::msleep(10);
    QThread::msleep(50);
    sendTcpMsg(msg);
    m_indexSendCmdList++;   // 待发送的报文序号移动下一个
}
